﻿using System;
using System.Disposables;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Ria.ApplicationServices;
using SoftSource.Common;
using SoftSource.MVVMC;
using SoftSource.Reactive;

namespace SoftSource.Controls
{
    public partial class LoginView : UserControl, IDisposable, IView<ILoginViewModelConsume>
    {
        #region Fields
        private CompositeDisposable compositeDisposable;
        #endregion Fields

        public LoginView()
        {
            InitializeComponent();

            this.compositeDisposable = new CompositeDisposable();
            
            Loaded += new RoutedEventHandler(LoginView_Loaded);

            // If the form loses focus when we start up, take focus back and stop watching for the event.
            FutureDisposable future = new FutureDisposable();
            future.Set(Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
                handler => (sender, e) => handler(sender, e),
                handler => this.loginForm.LostFocus += handler,
                handler => this.loginForm.LostFocus -= handler)
                .Do(evnt => this.FocusUsernameField())
                .Do(evnt => future.Dispose())
                .Subscribe());
        }

        #region Events
        private void LoginView_Loaded(object sender, RoutedEventArgs e)
        {
            System.Windows.Browser.HtmlPage.Plugin.Focus();
            this.loginForm.ContentLoaded += (sender2, e2) => this.FocusUsernameField();
        }

        private void FocusUsernameField()
        {
            var username = this.loginForm.FindNameInContent("UsernameTextbox") as TextBox;
            if (username != null)
                username.Focus();
        }

        /// <summary>
        ///     Submits the <see cref="LoginOperation"/> to the server
        /// </summary>
        private void LoginButton_Click(object sender, EventArgs e)
        {
            // If there was a validation error in a previously login attempt, clear it
            this.loginForm.ValidationSummary.Errors.Clear();
            
            if (this.loginForm.ValidateItem())
            {
                this.activity.IsBusy = true;
                this.ViewModel.Login
                    .Nullable()
                    .Finally(() => this.activity.IsBusy = false)
                    .Where(success => !success)
                    .Do(success => this.loginForm.ValidationSummary.Errors.Add(new ValidationSummaryItem("The username or password is incorrect")))
                    .Subscribe();
            }
        }

        /// <summary>
        ///     Enables the OK button if both username and password are not empty, disable it
        ///     otherwise
        /// </summary>
        private void EnableOrDisableOKButton(object sender, EventArgs e)
        {
            this.loginButton.IsEnabled = !(
                String.IsNullOrEmpty(((TextBox)this.loginForm.FindNameInContent("UsernameTextbox")).Text) ||
                String.IsNullOrEmpty(((PasswordBox)this.loginForm.FindNameInContent("Password")).Password));
        }

        /// <summary>
        ///     If a login operation is in progress and is cancellable, cancel it.
        ///     Otherwise, closes the window
        /// </summary>
        private void CancelButton_Click(object sender, EventArgs e)
        {
            this.ViewModel.Cancel.TryInvoke();
        }

        /// <summary>
        ///     Maps Esc to the cancel button and Enter to the
        ///     OK button
        /// </summary>
        private void LoginPanel_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                this.CancelButton_Click(this.loginCancel, new EventArgs());
            }
            else if (e.Key == Key.Enter && this.loginButton.IsEnabled)
            {
                this.LoginButton_Click(this.loginButton, new EventArgs());
            }
        }
        #endregion Events

        #region IView<ILoginViewModelConsume> Members

        public ILoginViewModelConsume ViewModel
        {
            get { return this.DataContext as ILoginViewModelConsume; }
            set { this.DataContext = value; }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            this.compositeDisposable.Dispose();
            GC.SuppressFinalize(this);
        }

        #endregion

        ~LoginView()
        {
            this.Dispose();
        }
    }
}
